mosquittoとIoTCoreを使用してTLSでMQTT通信をやってみた(mTLS、パスワード認証)

mosquittoとIoTCoreを使用してTLSでMQTT通信をやってみた(mTLS、パスワード認証)

Clock Icon2024.12.20

よくMQTTでブローカーとして使用されるmosquittoをローカルのコンテナで立ち上げ、IoTCoreとTLSで通信する手順をまとめます。

MQTTやIoTCoreに関する基本的な説明は省きますが、初心者の方でもわかりやすいように図で補足しながら進めます、全体の構成をイメージできるようになれば幸いです。

バージョン情報

  • mosquitto : 2.0.20
  • Openssl : 3.4.0

前置き

今回作る構成のイメージはこちら
ローカル端末のDockerにてmosquittoを立ち上げ、これをブローカーとします。
そしてローカルのターミナルとIoTCoreでパブリッシュ、サブスクライブをしてメッセージの送受信を行います。

 2024-12-12 17.29.07

IoTCore 準備

まずはIoTCore側の準備から始めます
 2024-12-13 16.10.38

証明書作成

セキュリティ → 証明書 で、「証明書を追加」

 2024-12-13 16.11.59

証明書のステータスを「アクティブ」にして「作成」
 2024-12-13 16.14.48

すると以下の証明書や鍵をダウンロードする画面が表示されます
今回は必要な物のみダウンロード

  • デバイス証明書
  • プライベートキーファイル(秘密鍵)
  • Amazon 信頼サービスエンドポイント-Amazon ルートCA1(CA証明書)

 2024-12-13 16.15.47

ダウンロードしたファイルを作業ディレクトリに配置
certs/iotcoreにおきます
わかりやすくするために名前も変更しておきましょう

 2024-12-13 16.33.13

 2024-12-13 16.33.58

続いて、先ほど作成した証明書に適用するポリシーを作成します

IoTCoreにて、セキュリティ → ポリシー で「ポリシーを作成」

 2024-12-13 16.34.12

ポリシー名とポリシードキュメントを入力
今回はテストのため、ポリシーアクションもポリシーリソースも * にしておきます
 2024-12-13 16.35.03

ちなみにJsonだとこんな感じ

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "*",
      "Resource": "*"
    }
  ]
}

ポリシーを作成したら証明書にアタッチします
ということで作成した証明書の画面に入り、「ポリシーをアタッチ」
 2024-12-13 16.35.32

作成したポリシーを選択
 2024-12-13 16.36.29

これでIoTCore側の準備は完了です

証明書類の作成

TLS通信のため証明書類を作成する手順です、オレオレ証明書で進めます。

今回はローカルのターミナルをクライアント、ローカルのmosquittoコンテナをサーバーとして相互TLS認証(mTLS)をする方針でいきます。

TLS通信周りの話は証明書やら鍵やらがたくさん出てきてわかりにくいと思うので、図を混ぜながら解説します。

こちらも参考に
https://dev.classmethod.jp/articles/eetann-learn-mtls/

CA

CAの秘密鍵の作成

openssl genrsa 2048 > ca.key

CA証明書の作成

openssl req -new -x509 -days 1826 -key ca.key -out ca.crt

サーバー側

サーバーの秘密鍵の作成

openssl genrsa 2048 > server.key

サーバーのCSR作成

openssl req -new -out server.csr -key server.key 

CAによる署名

openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 360

クライアント側

クライアントの秘密鍵の作成

openssl genrsa 2048 > client.key

クライアントのCSR作成

openssl req -new -out client.csr -key client.key 

CAによる署名

openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 360


ここまで進めると、下記のように9つのファイルが出力されていると思います
 2024-12-13 16.37.39

続いてフォルダの整理をやっていきます

certs/にmosquittoフォルダを作成し、以下のファイルを格納します

  • CA証明書
  • サーバーの秘密鍵
  • サーバー証明書

 2024-12-13 16.37.48

Dockerfile 作成

続いて、作業ディレクトリにDockerfileとmosquittoの設定ファイルである「mosquitto.conf」を作成します

まずはDockerfile

Dockerfile

FROM eclipse-mosquitto:2.0

# 設定ファイル,証明書フォルダをコピー
COPY ./mosquitto.conf /mosquitto/config/mosquitto.conf
COPY ./certs /mosquitto/config/certs

# ポートの公開
EXPOSE 8883

mosquitto.confの作成

mosquittoの設定ファイルです、サーバー証明書、IoTCoreの証明書、IoTCoreのアドレス、ログ設定などいろいろな設定をこのファイルで定義します

設定項目に関する公式ドキュメント
https://mosquitto.org/man/mosquitto-conf-5.html

# Mosquittoのリスナー設定
listener 8883
protocol mqtt

# CA証明書,サーバー証明書,秘密鍵
cafile /mosquitto/config/certs/mosquitto/ca.crt
certfile /mosquitto/config/certs/mosquitto/server.crt
keyfile /mosquitto/config/certs/mosquitto/server.key

# AWS IoT Coreへの接続設定
connection aws-iot
address ************.iot.ap-northeast-1.amazonaws.com:8883

# AWS IoT Coreのトピック設定
topic # both

# AWS IoT Core用のTLS設定
bridge_cafile /mosquitto/config/certs/iotcore/RootCA.pem
bridge_certfile /mosquitto/config/certs/iotcore/cert.crt
bridge_keyfile /mosquitto/config/certs/iotcore/private.key

# 相互認証
require_certificate true
use_identity_as_username true  # クライアント証明書のCNをユーザー名で使用する

# ログ設定
log_dest stdout            # ログをstdout(標準出力)に出力する
log_type all               # すべてのログを出力する
log_timestamp true         # ログにタイムスタンプを付与する 
connection_messages true   # クライアントの接続/切断のメッセージも付与する

# ブリッジ設定
bridge_insecure false
start_type automatic
notifications false
try_private true

編集が必要なのは下記の部分です

# AWS IoT Coreへの接続設定
connection aws-iot
address ************.iot.ap-northeast-1.amazonaws.com:8883

このaddressに、IoTCoreのドメインを設定します
IoTCoreはデフォルトで1つドメインを作成してくれているので、今回はそれを使用します

IoTCoreの「設定」
 2024-12-18 16.39.02

ドメイン設定を表示(どちらでもOK)
 2024-12-18 16.39.22

ドメイン名をコピーして先ほどの設定ファイルの値を更新
※リージョンによってドメインが変わります 今回は東京リージョンで進めます
 2024-12-18 16.39.39

address ************.iot.ap-northeast-1.amazonaws.com:8883

末尾の「:8883」はポート番号のため消さないように注意

今の作業ディレクトリの状況

.
├── Dockerfile
├── ca.key
├── ca.srl
├── certs
│   ├── iotcore
│   │   ├── RootCA.pem
│   │   ├── cert.crt
│   │   └── private.key
│   └── mosquitto
│       ├── ca.crt
│       ├── server.crt
│       └── server.key
├── client.crt
├── client.csr
├── client.key
├── mosquitto.conf
└── server.csr

データの送受信を確認

すべての設定が済んだので、Dockerコンテナを立ち上げMQTTのメッセージ送受信をしていきます

Dockerビルド、コンテナ起動

docker build -t my-mosquitto . 
docker run --rm -d --name mqtt-test -p 8883:8883 my-mosquitto

※ --rm オプションでコンテナ停止後、そのままコンテナを削除するようにしてます。

IoTCore テストクライアントの準備

東京リージョンにして、「MQTTテストクライアント」
IoTCore側の操作(サブスクライブ、パブリッシュ)はこの画面で行います。
 2024-12-18 16.53.37

ローカル端末の名前解決

サーバー証明書のCommon Nameを「locahost」と設定し、ローカル端末からmosquittoコマンドを実行するときのホスト名も「locahost」と指定するため、ローカル端末がlocahostというホスト名を名前解決できるか確認しておきます。

Macの場合、以下のコマンドでホストファイルを確認できます

cd ~
sudo vim /private/etc/hosts

 2024-12-18 16.54.28

127.0.0.1とlocalhostの組があればOKです。

(自分の場合は最初から127.0.0.1とlocalhostが紐づいていました)

ローカル端末からパブリッシュ

まずはローカル端末のターミナルよりmosquittoコマンドを使用してMQTTメッセージをパブリッシュし、IoTCoreでサブスクライブしてみます

図だとこんな感じです、コマンド実行時証明書にアクセスする必要があるため、ターミナルは作業ディレクトリに入っておきます。
 2024-12-18 17.08.49

IoTCore サブスクライブ

まずはMQTTテストクライアントにてサブスクライブの設定

「トピックをサブスクライブする」のタブでトピックのフィルターを入力します。
今回は「test/topic」という名前でやり取りすることにします。
 2024-12-18 16.54.14

ローカル端末 パブリッシュ

IoTCoreの待ち受けが完了したのでターミナルからパブリッシュをしていきます
今回はmosquitto_pubコマンドを使用します

mosquitto_pub \
    --cert      client.crt \
    --key       client.key \
    --cafile    ./certs/mosquitto/ca.crt \
    -h          localhost \
    -t          "test/topic" \
    -m          '{"device_name": "test-sensor-001"}'
  • --cert … クライアント証明書
  • --key … クライアントの秘密鍵
  • --cafile … CA証明書
  • -h … 宛先
  • -t … トピック名(先ほどIoTCoreで入力したトピックをここに)
  • -m … メッセージ本文

mosquitto_pubに関するドキュメント
https://mosquitto.org/man/mosquitto_pub-1.html

こちらを実行し、データの送受信が成功するとIoTCore側で送信したメッセージが確認できます。
 2024-12-18 16.54.57

IoTCoreからパブリッシュ

次は逆向きでデータを送受信します。
 2024-12-18 17.09.14

ローカル端末 サブスクライブ

今度は「mosquitto_sub」コマンドを使用します
コマンドの内容はpubの時から-m属性を抜かしたものと一緒です。

mosquitto_sub \
    --cert      client.crt \
    --key       client.key \
    --cafile    ./certs/mosquitto/ca.crt \
    -h          localhost \
    -t          "test/topic"

mosquitto_subに関するドキュメント
https://mosquitto.org/man/mosquitto_sub-1.html

コマンド実行後、待ち受け状態になったら次に進みます
 2024-12-18 16.55.07

IoTCore パブリッシュ

MQTTテストクライアントの、「トピックに公開する」タブを開き、先ほどローカル側で-tにて指定したトピック(test/topic)と、メッセージ本文を入力して「発行します」
 2024-12-18 16.55.18

すると待ち受け状態のターミナルにメッセージが受信されます。
 2024-12-18 16.55.28

これでmosquittoコンテナをブローカーとしてローカル端末とIoTCore間でMQTTのやり取りができました。

おまけ TLSをパスワード認証でやってみる

mosquittoでTLS通信を行う際、相互認証のほかにパスワード認証も機能することを確認できました。
相互認証ではクライアント証明書が必要でしたが、パスワード認証だとユーザー名とパスワードでTLS通信が実施できます。

必要な手順

作業ディレクトリにユーザー名とパスワードの組を記入したパスワードファイルを生成します
pass.txt

user001:password001

以下のコマンドでパスワードを暗号化とファイルの権限を変更します

mosquitto_passwd -U pass.txt
chmod 0700 ./pass.txt

これで、pass.txtのpassword001の部分が暗号化されます

Dockerfile

作成したパスワードファイルを配置するため以下の行を追加します

COPY ./pass.txt /mosquitto/config/pass.txt

mosquitto.conf

mosquitto.confにパスワード認証のための設定を追加します

password_file /mosquitto/config/pass.txt

これでDockerコンテナを起動し、メッセージパブリッシュ時のコマンドに-u、-Pオプションを追加すれば、パスワード認証によるTLS通信ができるようになります
-uがユーザー名、-Pがパスワードのため、今回の例だとこんな感じ

mosquitto_pub \
    --cafile    ./certs/mosquitto/ca.crt \
    -h          localhost \
    -t          "test/topic" \
    -m          '{"device_name": "test-sensor-001"}'
    -u user001 \
    -P password001

以上、参考になれば幸いです

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.